//
//  MKUIPickerCycleView.m
//  MKUI
//
//  Created by sushangjin on 2020/6/5.
//  Copyright © 2020 sushangjin. All rights reserved.
//

#import "MKUIPickerCycleView.h"
#import "UIColor+MKUI.h"
@interface MKUIPickerCycleView()<UIPickerViewDataSource,UIPickerViewDelegate>
@property(nonatomic,weak,nullable) id<UIPickerViewDataSource> forwardDataSource;
@property(nonatomic,weak,nullable) id<UIPickerViewDelegate> forwardDelegate;
@property(nonatomic,assign) NSInteger maxCount;
@property(nonatomic,assign) NSInteger minPageCount;
@property(nonatomic,strong) NSMutableDictionary<NSNumber*,NSNumber *> *originRowsCache;
@property(nonatomic,strong) NSMutableDictionary<NSNumber*,NSNumber *> *enableCycleSelectMap;
@end

@implementation MKUIPickerCycleView
- (void)enableCycleSelectForAllComponent:(BOOL)enable{
    NSInteger n = [self numberOfComponents];
    for (int i=0; i<n; i++) {
       self.enableCycleSelectMap[@(i)] = @(enable);
    }
    [self reloadAllComponents];
}

- (void)enableCycleSelect:(BOOL)enable forComponent:(NSInteger)component{
    if([self isEnableCycleSelectForComponent:component]!=enable){
        self.enableCycleSelectMap[@(component)] = @(enable);
        NSInteger n = self.numberOfComponents;
        if(component<n){
            [self reloadComponent:component];
        }
    }
}
- (BOOL)isEnableCycleSelectForComponent:(NSInteger)component{
    BOOL en = self.enableCycleSelectMap[@(component)].boolValue;
    return en;
}
- (id)initWithFrame:(CGRect)frame{
    if (self=[super initWithFrame:frame]) {
        [self __init_MKUIPickerCycleView];
    }
    return self;
}
- (id)initWithCoder:(NSCoder *)coder{
    if (self=[super initWithCoder:coder]) {
        [self __init_MKUIPickerCycleView];
    }
    return self;
}
- (void)__init_MKUIPickerCycleView{
    self.maxCount = 1000;
    self.minPageCount = 3;
    self.originRowsCache = [[NSMutableDictionary alloc] init];
    self.enableCycleSelectMap = [[NSMutableDictionary alloc] init];
    self.backgroundColor = [UIColor mk_colorWithLight:UIColor.blackColor dark:UIColor.whiteColor];
}
- (void)setDelegate:(id<UIPickerViewDelegate>)delegate{
    [super setDelegate:self];
    self.forwardDelegate = delegate;
}
- (void)setDataSource:(id<UIPickerViewDataSource>)dataSource{
    [super setDataSource:self];
    self.forwardDataSource = dataSource;
}

- (NSInteger)originRowsOfComponent:(NSInteger)component{
    NSInteger r = self.originRowsCache[@(component)].integerValue;
    return r;
}
- (NSInteger)converRow:(NSInteger)row forComponent:(NSInteger)component{
    if(![self isEnableCycleSelectForComponent:component]){
        return row;
    }
    NSInteger originRows = [self originRowsOfComponent:component];
    NSInteger r = originRows>0?row%originRows:row;
    return r;
}
#pragma mark - override
- (void)reloadAllComponents{
    NSInteger n = self.numberOfComponents;
    for (int i=0; i<n; i++) {
        [self reloadComponent:i];
    }
}
- (void)reloadComponent:(NSInteger)component{
    [super reloadComponent:component];
    if([self isEnableCycleSelectForComponent:component]){
        NSInteger row = [self selectedRowInComponent:component];
        dispatch_async(dispatch_get_main_queue(), ^{
            [self selectRow:row inComponent:component animated:NO];
        });
    }
}
- (NSInteger)numberOfRowsInComponent:(NSInteger)component{
    NSInteger rows = [self originRowsOfComponent:component];
    return rows;
}
- (nullable UIView *)viewForRow:(NSInteger)row forComponent:(NSInteger)component{
    NSInteger originRows = [self converRow:row forComponent:component];
    UIView *view = [super viewForRow:originRows forComponent:component];
    return view;
}
- (void)selectRow:(NSInteger)row inComponent:(NSInteger)component animated:(BOOL)animated{
    NSInteger reversedRow = [self __reversedRow:row forComponent:component nestToSelectRow:animated];
    [super selectRow:reversedRow inComponent:component animated:animated];
}
- (NSInteger)selectedRowInComponent:(NSInteger)component{
    NSInteger row = [super selectedRowInComponent:component];
    if(row<0){
        return row;
    }
    NSInteger originRows = [self converRow:row forComponent:component];
    return originRows;
}
- (NSInteger)__reversedRow:(NSInteger)originRow forComponent:(NSInteger)component nestToSelectRow:(BOOL)nestToSelectRow{
    if(![self isEnableCycleSelectForComponent:component]){
        return originRow;
    }
    NSInteger reversedRow = 0;
    NSInteger pageRows = [super numberOfRowsInComponent:component];
    NSInteger originPageRows = 0;
    if(self.originRowsCache[@(component)]==nil){
        originPageRows = [self __originNumberOfRowsInComponent:component];
    }else{
        originPageRows = [self originRowsOfComponent:component];
    }
    if(originPageRows){
        NSInteger centerPage = (pageRows/originPageRows)*0.5;
        if(nestToSelectRow){
            NSInteger currentSelectRow = [super selectedRowInComponent:component];
            NSInteger currentPage = currentSelectRow/originPageRows;
            NSInteger reversedRow1 = currentPage*originPageRows+originRow;
            NSInteger reversedRow2 = (currentPage+1)*originPageRows+originRow;
            NSInteger reversedRow3 = (currentPage-1)*originPageRows+originRow;
            NSMutableArray<NSNumber *> *list = [[NSMutableArray alloc] initWithCapacity:3];
            [list addObject:@(reversedRow1)];
            if(reversedRow2<[super numberOfRowsInComponent:component]){
                [list addObject:@(reversedRow2)];
            }
            if(reversedRow3>=0){
                [list addObject:@(reversedRow3)];
            }
            NSInteger dis = NSIntegerMax;
            //找出离currentSelectRow最近的位置
            for (NSNumber *n in list) {
                NSInteger d = ABS(n.integerValue-currentSelectRow);
                if(d<dis){
                    dis = d;
                    reversedRow = n.integerValue;
                }
            }
        }else{
            reversedRow = centerPage*originPageRows+originRow;
        }
    }
    return reversedRow;
}
- (NSInteger)__originNumberOfRowsInComponent:(NSInteger)component{
    NSInteger rows = 0;
    if(self.forwardDataSource){
        rows = [self.forwardDataSource pickerView:self numberOfRowsInComponent:component];
        self.originRowsCache[@(component)] = @(rows);
    }
    return rows;
}
#pragma mark - delegate:UIPickerViewDataSource
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
    NSInteger count = 0;
    if(self.forwardDataSource){
        count = [self.forwardDataSource numberOfComponentsInPickerView:pickerView];
    }
    return count;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
    NSInteger rows = 0;
    if(self.forwardDataSource){
        rows = [self.forwardDataSource pickerView:self numberOfRowsInComponent:component];
        if([self isEnableCycleSelectForComponent:component]&&rows>0){
            NSInteger pageCount = ceil(self.maxCount/rows);
            pageCount = MAX(self.minPageCount,pageCount);
            self.originRowsCache[@(component)] = @(rows);
            rows = rows*pageCount;
        }
    }
    return rows;
}
#pragma mark - delegate:UIPickerViewDelegate
// returns width of column and height of row for each component.
- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component API_UNAVAILABLE(tvos){
    CGFloat w = 0;
    if([self.forwardDelegate respondsToSelector:_cmd]){
        w = [self.forwardDelegate pickerView:pickerView widthForComponent:component];
    }
    return w;
}
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component API_UNAVAILABLE(tvos){
    CGFloat h = 44;
    if([self.forwardDelegate respondsToSelector:_cmd]){
        h = [self.forwardDelegate pickerView:pickerView rowHeightForComponent:component];
    }
    return h;
}
// these methods return either a plain NSString, a NSAttributedString, or a view (e.g UILabel) to display the row for the component.
// for the view versions, we cache any hidden and thus unused views and pass them back for reuse.
// If you return back a different object, the old one will be released. the view will be centered in the row rect
- (nullable NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component API_UNAVAILABLE(tvos){
    NSString *title = nil;
    if([self.forwardDelegate respondsToSelector:_cmd]){
        NSInteger originRow = [self converRow:row forComponent:component];
        title = [self.forwardDelegate pickerView:pickerView titleForRow:originRow forComponent:component];
    }
    return title;
}
- (nullable NSAttributedString *)pickerView:(UIPickerView *)pickerView attributedTitleForRow:(NSInteger)row forComponent:(NSInteger)component API_AVAILABLE(ios(6.0)) API_UNAVAILABLE(tvos){
    NSAttributedString *title = nil;
    if([self.forwardDelegate respondsToSelector:_cmd]){
        NSInteger originRow = [self converRow:row forComponent:component];
        title = [self.forwardDelegate pickerView:pickerView attributedTitleForRow:originRow forComponent:component];
    }
    return title;
}
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(nullable UIView *)view API_UNAVAILABLE(tvos){
    UIView *v = view;
    if([self.forwardDelegate respondsToSelector:_cmd]){
        NSInteger originRow = [self converRow:row forComponent:component];
        v = [self.forwardDelegate pickerView:pickerView viewForRow:originRow forComponent:component reusingView:view];
    }
    return v;
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component API_UNAVAILABLE(tvos){
    if([self.forwardDelegate respondsToSelector:_cmd]){
        NSInteger originRow = [self converRow:row forComponent:component];
        [self.forwardDelegate pickerView:pickerView didSelectRow:originRow inComponent:component];
        if([self isEnableCycleSelectForComponent:component]){
            [self selectRow:originRow inComponent:component animated:NO];
        }
    }
}
@end
